home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / romize.zip / TCROM.DOC < prev   
Text File  |  1989-02-02  |  14KB  |  344 lines

  1. WRITING ROMABLE CODE IN TURBO C:
  2.  
  3. Updated 2/2/89 for Turbo C 2.0 by the author.
  4.  
  5.     I recently completed a consulting project to design a
  6. special-purpose controller using an embedded 8088 with firmware
  7. in ROM. To create the firmware, I developed a scheme for
  8. generating ROMable code from Turbo C.
  9.  
  10.     The scheme utilizes the following:
  11.  
  12.     1. Rules for writing C code.
  13.  
  14.     2. ROMIZE.C, a program to post-process the Turbo C Compiler
  15. assembler output.
  16.  
  17.     3. INSJUMP.C, a program to patch the ROM binary code to
  18. insert a restart jump instruction.
  19.  
  20.     4. BINTOHEX.C, a program to produce Intel-format files for
  21. downloading ROM images to an EPROM programmer.
  22.  
  23.     5. C0ROMX.ASM, a replacement for C0.ASM, the startup code.
  24.  
  25.     In addition, the scheme requires the Turboc C command-line
  26. compiler, TCC.EXE; an assembler, Microsoft Version 3.0 or later,
  27. or equivalent (I use Microsoft V5.0); TLINK or MS-Link; and
  28. EXE2BIN (more about EXE2BIN later).
  29.  
  30.     The scheme involves the following steps:
  31.  
  32.     1. C code is written following a few rules.
  33.  
  34.     2. TCC is used to translate the C code to assembly.
  35.  
  36.     3. ROMIZE is used to perform certain modifications to the
  37. assembly code.
  38.  
  39.     4. The modified assembly code is assembled into a .OBJ file.
  40.  
  41.     5. The .OBJ file is linked with the C0ROMX.OBJ startup code
  42. and with other .OBJ files (if needed; these may be from C code
  43. that has gone through the four above steps, or routines
  44. originally coded in assembly).  This produces a .EXE file.
  45.  
  46.     6. EXE2BIN converts the .EXE into a binary ROM image.
  47.  
  48.     7. INSJUMP inserts the reset jump into the ROM image.
  49.  
  50.     8. If necessary, the binary ROM image is converted into
  51. whatever format the particular EPROM programmer requires. (Mine
  52. is a plug-in card for the PC which takes binary format directly,
  53. so I don't have to do this step.)
  54.  
  55.     All these steps can be run in a .BAT or MAKE file, making the
  56. conversion of the original C code to ROM code almost automatic.
  57.  
  58. RULES AND ASSUMPTIONS:
  59.  
  60.     The rules and assumptions for writing ROMable code using this
  61. scheme are as follows:
  62.  
  63.     1. The Compact memory model (small code, large data) is used.
  64. This results in a maximum of 64K of code and initialized static
  65. variables (i.e. constants) but up to 1 MB of Data space.
  66.  
  67.     2. Initialized static variables are considered constants, and
  68. may not be changed during program execution because they are
  69. stored in ROM.
  70.  
  71.     3. Variables defined as "extern" are considered constants.
  72. Such variables would be used for font tables, for example.  True
  73. "variables" (which change during program execution) may not be
  74. defined in one C module and declared as "extern" in another.  The
  75. only means of inter-module variable passing is through function
  76. parameters and return values (a good programming practice
  77. anyway). IT IS OK to define variables in a C module and reference
  78. these as EXTRN's in assembler-coded modules, however.
  79.  
  80.     4. Most of the Runtime Library routines may NOT be used,
  81. because they have been compiled with the wrong segment groupings
  82. for the ROM environment.  Many of the library routines are not
  83. usable, anyway, because they pertain to the DOS environment and
  84. use system facilities that are not available in the ROM
  85. environment.  Library routines that are needed will have to be
  86. recreated, either in C or assembly.  You may want to order the
  87. Turbo C Runtime Library from Borland as a starting point. I
  88. ordered the Runtime Library several months into the project that
  89. stimulated the creation of this system, but I didn't really need
  90. it.
  91.  
  92.     I was able to compile and debug over 90% of my code (which
  93. was about 3,500 lines of C) using the Integrated Environment on a
  94. PC, then re-compile (with #DEFINES and #IFDEFs to accommodate the
  95. environmental differences) for ROM with little further debugging.
  96.  
  97. SEGMENT USAGE IN TURBO C:
  98.  
  99.     Turbo C assigns uninitialized static variables to a segment
  100. called _BSS and initialized static variables (i.e., constants) to
  101. a segment called _DATA. These two segments are associated via a
  102. GROUP directive, and assumed, under normal circumstances, to be
  103. jointly addressable by the DS register.  Instructions are
  104. generated in the _TEXT segment, and assumed addressable by the CS
  105. register.
  106.  
  107.     In the ROM environment, the constants in the _DATA segment
  108. and the code in the _TEXT segment are both located in the ROM and
  109. addressed by CS.  Only BSS is addressed by DS.  Therefore to
  110. convert the code generated by the compiler, ROMIZE is used as
  111. follows:
  112.  
  113. WHAT ROMIZE DOES:
  114.  
  115.     ROMIZE makes two passes through the assembly source code
  116. generated by the command line compiler.  In the first pass, it
  117. reads the code and accumulates a table of all symbols defined in
  118. the _DATA segment.  There are only a few such symbols, since
  119. Turbo C places all string constants in a single symbol "s@", and
  120. refers to individual strings as "s@+n".  Likewise, all
  121. non-string constants are part of a single symbol called "d@" and
  122. referred to by their displacements.  There are however, a large
  123. number of references to these symbols in the code.
  124.  
  125.     In its second pass, ROMIZE re-reads the source code and
  126. writes it out with modifications.  The modifications are:
  127.  
  128.     1. The command that groups _BSS and DATA together into DGROUP
  129. is changed so that only _BSS is in DGROUP.
  130.  
  131.     2. A new GROUP command is inserted creating CGROUP as _TEXT
  132. and _DATA.
  133.  
  134.     3. The ASSUME statement is changed from
  135.         ASSUME cs:_TEXT,ds:DGROUP
  136.           to:
  137.         ASSUME cs:CGROUP,ds:DGROUP
  138.  
  139.     4. In any line of code with a reference to a symbol in the
  140. _DATA segment, the group reference is changed from DGROUP to
  141. CGROUP, or a CGROUP reference is added if no group name is
  142. present.
  143.  
  144.     5. Preceding a line of code with a reference to a symbol in
  145. the _DATA segment may be a "mov x,ds" or a "push ds"instruction.
  146. This is changed to a "mov x,cs" or "push cs".
  147.  
  148.     6. Following a line of code with a reference to a symbol in
  149. the _DATA segment may be a "push ds" instruction. This is changed
  150. to a "push cs".
  151.  
  152.     In order to do the looking backward and forward, ROMIZE
  153. maintains a three-line pipeline, reading new lines into the head
  154. of the pipe and writing lines from the end.
  155.  
  156.     The various segment naming options of the compiler do not
  157. produce the desired changes for the ROM environment. I would be
  158. happy to pursue this subject further with anyone who is curious
  159. about it.
  160.  
  161. LINKING:
  162.  
  163.     You can use either TLINK or MS-LINK. The command line will,
  164. of course be different for each. The "Warning - no stack segment"
  165. will be produced by either. This is normal.
  166.  
  167.     You must read the link map carefully to verify that your code
  168. fit in the size of ROM you use. Consider the following partial
  169. link map:
  170.  
  171. LINK : warning L4021: no stack segment
  172.  
  173.  Start  Stop   Length Name                   Class
  174.  00000H 05A74H 05A75H _TEXT                  CODE
  175.  05A80H 07DF7H 02378H _DATA                  DATA
  176.  07DF8H 0A530H 02739H _BSS                   BSS
  177.  0A531H 0A531H 00000H _BSSEND                BSSEND
  178.  
  179.  Origin   Group
  180.  0000:0   CGROUP
  181.  07DF:0   DGROUP
  182.  
  183.     The .bin file that came out of EXE2BIN for the module that
  184. produced this link map was A531 (hex) bytes long, however, this
  185. module does fit in 32K. The key indicator is the sum of the
  186. lengths of _TEXT and _DATA, and consequently, the starting
  187. address of DGROUP (_BSS). Here it is 7DF8, about 500 bytes
  188. under 32K.
  189.  
  190. MORE ABOUT EXE2BIN:
  191.  
  192.     EXE2BIN is needed to convert the .EXE file into a binary
  193. image that can be transmitted to an EPROM programmer. It may need
  194. to perform "segment fixups" (segment relocation), if your program
  195. includes constructs like the following:
  196.  
  197.   static char *menu[] = {"Preview   ","Add Before","Add After "};
  198.  
  199.     This is a convenient way to generate arrays of strings for
  200. such things as menus.  This generates an array of pointers whose
  201. segment parts must be relocated by EXE2BIN to the segment address
  202. of the ROM.  Therefore, when the EXE2BIN step is run, you will be
  203. prompted to enter a segment address (F800 hex in